package net.anzix.jhacks.flexclipse.builder;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import net.anzix.jhacks.flexclipse.Activator;
import net.anzix.jhacks.flexclipse.properties.ProjectPropertyLoader;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Platform;
import org.osgi.framework.Bundle;

import flex2.tools.oem.Application;
import flex2.tools.oem.Configuration;
import flex2.tools.oem.VirtualLocalFile;
import flex2.tools.oem.VirtualLocalFileSystem;

public class FlexclipseBuilder extends IncrementalProjectBuilder {

	public static final String BUILDER_ID = "net.anzix.jhacks.flexclipse.flexclipseBuilder";
	static final String MARKER_TYPE = "net.anzix.jhacks.flexclipse.mxmlProblem";

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.core.internal.events.InternalBuilder#build(int,
	 *      java.util.Map, org.eclipse.core.runtime.IProgressMonitor)
	 */
	@SuppressWarnings("unchecked")
	protected IProject[] build(int kind, Map args, IProgressMonitor monitor)
			throws CoreException {
		fullBuild(monitor);
		return null;
	}

	protected void fullBuild(final IProgressMonitor monitor)
			throws CoreException {
		try {

			final ProjectPropertyLoader loader = new ProjectPropertyLoader(
					getProject());

			getProject().deleteMarkers(IMarker.PROBLEM, true,
					IResource.DEPTH_INFINITE);
			final Application application = new Application(getVirtualLocalFiles(loader));
			final Configuration configuration = application
					.getDefaultConfiguration();
			configuration.setContextRoot(getProjectHome() + File.separator + loader.getSourceDir());
			configuration.addConfiguration(new File(getFlexHome()
					+ File.separator + "frameworks" + File.separator
					+ "flex-config.xml"));
			final IFile file = getProject().getFile(loader.getOutput());
			application.setOutput(new File(getProjectHome()
					+ loader.getOutput()));
			configuration.addIncludes(new String[]{getProjectHome() + File.separator + loader.getSourceDir()});

			for(final String lib : loader.getLibraries()) {
				configuration.addLibraryPath(new File[]{new File(lib)});
			}
			configuration.optimize(false);

			application.setLogger(new ConsoleLogger(getProject()));
			application.setProgressMeter(new FlexBuildProgressMeter(monitor));

			final long result = application.build(true);
			file.refreshLocal(IResource.DEPTH_ONE, monitor);
			if (result < 0) {
				final IMarker buildFailedMarker = getProject().createMarker(
						MARKER_TYPE);
				buildFailedMarker.setAttribute(IMarker.SEVERITY,
						IMarker.SEVERITY_ERROR);
				buildFailedMarker.setAttribute(IMarker.MESSAGE,
						"Build failed, see details!");
			}
		} catch (final IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private VirtualLocalFile[] getVirtualLocalFiles(final ProjectPropertyLoader loader) throws IOException {
		final List<VirtualLocalFile> localFiles = new ArrayList<VirtualLocalFile>();
		loader.getSourceDir();
		final IPath srcDir = getProject().getLocation().append(loader.getSourceDir());
		final File file = srcDir.toFile();
		final VirtualLocalFileSystem fileSystem = new VirtualLocalFileSystem();
		listAllMxml(file, localFiles, fileSystem);
		return localFiles.toArray(new VirtualLocalFile[]{});
	}

	private void listAllMxml(final File file, final List<VirtualLocalFile> localFiles, final VirtualLocalFileSystem fileSystem) throws IOException {
		for(String name : file.list()) {
			File child = new File(file, name);
			if(child.isFile() && child.getName().endsWith(".mxml")) {
				VirtualLocalFile virtualLocalFile = fileSystem.create(child.getCanonicalPath(), fileToText(child), file, child.lastModified());
				localFiles.add(virtualLocalFile);
			} else if (child.isDirectory()){
				listAllMxml(child, localFiles, fileSystem);
			}
		}
	}

	private String fileToText(File file) throws IOException {
		InputStream inputStream = null;
		try {
			inputStream = new FileInputStream(file);
			final BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
			final StringBuilder builder = new StringBuilder();
			String line = reader.readLine();
			while(line != null) {
				builder.append(line);
				builder.append('\n');
				line = reader.readLine();
			}
			return builder.toString();
		} finally {
			if(inputStream != null) {
				inputStream.close();
			}
		}
	}

	private String getFlexHome() throws IOException {
		final Bundle bundle = Platform.getBundle(Activator.FLEX_PLUGIN_ID);
		final URL entry = bundle.getEntry("/flexsdk");
		return (FileLocator.toFileURL((entry))).getPath();
	}

	private String getProjectHome() {
		return getProject().getLocation().toOSString().concat(File.separator);
	}

}
